package com.sunseen.capacitormachine.commumication.serialport;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.util.SparseIntArray;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;

import com.orhanobut.logger.Logger;
import com.sunseen.capacitormachine.CapacitorApp;
import com.sunseen.capacitormachine.R;
import com.sunseen.capacitormachine.common.SharePreferenceUtil;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CapacitorIdData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CapacitorIdJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CapacitorLevelData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CapacitorLevelJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CapacityData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CapacityJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CircuitData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.CompleteUidJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.DetectionResult;
import com.sunseen.capacitormachine.commumication.mqtt.bean.LeakCurrentData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.LeakCurrentJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.OpenCircuitJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.ResultData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.ShortCircuitJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.TemperatureData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.TemperatureJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.bean.UnAgeData;
import com.sunseen.capacitormachine.commumication.mqtt.bean.UnAgeJsonObj;
import com.sunseen.capacitormachine.commumication.mqtt.event.SendJsonObjEvent;
import com.sunseen.capacitormachine.commumication.serialport.bean.ChangeBatchBean;
import com.sunseen.capacitormachine.commumication.serialport.bean.OneStepInfo;
import com.sunseen.capacitormachine.commumication.serialport.event.AlarmEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.ChainCapacitorUpdateEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.ChainMoveOneStepEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.CmdEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.CmdSendFailedEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.HideAlarmViewEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.ImplosionCountEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.PlcReplyEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.RealTimeVoltageEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.ReplyPlcEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.SurgeUidEvent;
import com.sunseen.capacitormachine.commumication.serialport.event.UpdatePowerSupplyEvent;
import com.sunseen.capacitormachine.commumication.tcp.event.ChangeDetectStateEvent;
import com.sunseen.capacitormachine.data.Constant;
import com.sunseen.capacitormachine.data.DataUtil;
import com.sunseen.capacitormachine.data.ObjectBox;
import com.sunseen.capacitormachine.data.bean.CapacitorBean;
import com.sunseen.capacitormachine.data.bean.CapacitorBean_;
import com.sunseen.capacitormachine.data.bean.DetectionFlagBean;
import com.sunseen.capacitormachine.data.bean.HolderBean;
import com.sunseen.capacitormachine.data.bean.PosBean;
import com.sunseen.capacitormachine.modules.home.bean.PowerSupplyBean;
import com.sunseen.capacitormachine.modules.home.event.ChainHolderIntoOvenEvent;
import com.sunseen.capacitormachine.modules.home.event.OperationInfoEvent;
import com.sunseen.capacitormachine.modules.parameter.bean.ProcessParameter;
import com.sunseen.capacitormachine.modules.permission.operation.event.IndexInitEvent;
import com.sunseen.capacitormachine.modules.realtime.event.CountInfo;
import com.sunseen.capacitormachine.modules.realtime.event.CountUpdateEvent;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;

import android_serialport_api.SerialPort;
import io.objectbox.Box;
import io.objectbox.query.QueryBuilder;

/**
 * 与PLC通讯的服务
 *
 * @author zest
 */
public class PlcService extends Service {
    private final static String TAG = PlcService.class.getSimpleName();

    private static final String devicePath = "/dev/ttyS1";
    private static final int baudRate = 19200;

    private static final Handler handler = new Handler();

    private static final String UF = "uF";
    private static final String UA = "uA";
    private static final String OO = "00";

    private static final int frameHead = 0x55;

    private SerialPort mSerialPort;
    private OutputStream mOutputStream;
    private Thread runThread;

    private Box<CapacitorBean> capacitorBeanBox;

    private long lastRunTime = -10001;

    private String[] operateString;

    @Override
    public void onCreate() {
        super.onCreate();
        operateString = getResources().getStringArray(R.array.log_content);
        EventBus.getDefault().register(this);
        capacitorBeanBox = ObjectBox.getBoxStore().boxFor(CapacitorBean.class);
        QueryBuilder<CapacitorBean> queryBuilder = capacitorBeanBox.query();
        outCapacitorBean = queryBuilder.equal(CapacitorBean_.sequence, -1).build().findFirst();
        if (outCapacitorBean == null) {
            outCapacitorBean = new CapacitorBean("-1", -1, true);
            capacitorBeanBox.put(outCapacitorBean);
        }
        runThread = new Thread(parseRun, "PLC");
        runThread.start();
    }

    private volatile boolean canRun = true;

    private Runnable parseRun = new Runnable() {
        @Override
        public void run() {
            try {
                mSerialPort = new SerialPort(new File(devicePath), baudRate, 0);
                mOutputStream = mSerialPort.getOutputStream();
                final InputStream mInputStream = mSerialPort.getInputStream();
                int readSize;
                final byte[] buffers = new byte[255];
                while (canRun) {
                    try {
                        readSize = mInputStream.read(buffers);
                        if (readSize > 0) {
                            onDataReceive(buffers, readSize);
                        }
//                        Log.e(TAG, "readSize = " + readSize);
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.e(TAG, "PLC 串口读取线程异常");
                    }
                }
                Log.e(TAG, "PLC 串口读取线程结束");
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "PLC 串口开启发生异常");
            }
        }
    };

    private final int[] buf = new int[255];
    private int frameLength = 0;
    private boolean hasFrameHead = false;
    private int curPos = 0;

    /**
     * 接收到数据进行处理
     */
    private void onDataReceive(byte[] bytes, int size) {
        //进行数据解析
        for (int i = 0; i < size; i++) {
            int curInt = bytes[i] & 0xFF;
            if (hasFrameHead) {
                if (curPos == 1) {
                    switch (curInt) {
                        case 0x01:  //检测结果上报
                        case 0x02:  //启动请求上报
                        case 0x05:  //初始化成功后上报
                        case 0x06:  //烤箱内链条开始运动前上报
                        case 0x07:  //烤箱内链条运动后上报
                        case 0x08:  //暂停(停止状态)状态上报
                        case 0x09:  //复位状态上报
                            frameLength = 131;
                            buf[curPos] = curInt;
                            curPos++;
                            break;
                        //电源电压电流数据上报
                        case 0x03:
                            frameLength = 130;
                            buf[curPos] = curInt;
                            curPos++;
                            break;
                        case 0x04:  //异常状态上报
                            frameLength = 30;
                            buf[curPos] = curInt;
                            curPos++;
                            break;
                        //数据应答
                        case 0xAA:
                        case 0xBB:
                            frameLength = 3;
                            buf[curPos] = curInt;
                            curPos++;
                            break;
                        default:
                            //功能码错误
                            resetFrameFlag();
                            Log.e(TAG, "解析功能码错误!");
                            break;
                    }
                } else {
                    //已经是该帧的最后一个字节
                    if (curPos == frameLength - 1) {
                        buf[curPos] = curInt;
                        //已经获得一帧完整帧，进行解析处理
                        analysisFrame(buf);
                        resetFrameFlag();
                    } else if (curPos < frameLength) {
                        buf[curPos] = curInt;
                        curPos++;
                    } else {
                        //数据长度读取错误
                        resetFrameFlag();
                        Log.e(TAG, "数据长度读取错误!");
                    }
                }
            } else {
                if (curInt == frameHead) {
                    hasFrameHead = true;
                    buf[curPos] = curInt;
                    curPos++;
                } else {
                    //无帧头，数据错误
                    resetFrameFlag();
                    Log.e(TAG, "解析错误，数据无帧头!");
                }
            }
        }
//        if (BuildConfig.DEBUG) {
//            logDatas(bytes, size - 1);
//        }
    }

    private void resetFrameFlag() {
        hasFrameHead = false;
        curPos = 0;
        frameLength = 0;
    }

    private int ovenMoveCount = 0;

    private void analysisFrame(int[] frameData) {
        if (frameData[1] > 0x01 && frameData[1] < 0xAA) {
            //0x02 ~ 0x09 直接回复
            reply(true);
        }
        for(int i = 0; i < frameData.length; i++){
            Log.e("xiaochunhui--", Integer.toHexString(frameData[i]));
        }
        switch (frameData[1]) {
            case 0x01: {
                //检测结果上报
//                int sumCheck = 0;
//                for (int i = 3, size = pos - 2; i <= size; i++) {
//                    sumCheck += frameData[i];
//                }
//                sumCheck = sumCheck & 0xFF;
//                Log.e(TAG, "sumCheck = " + sumCheck);
//                if (sumCheck == frameData[pos - 1]) {//校验正确,处理数据
                //内爆结果进行分选
                if (DataUtil.flagBean.isImplosionEnable()) {
                    //内爆推料前一个位置上的电容有内爆则上报内爆结果
                    PosBean implosionPreOutPos = DataUtil.getChainPosBean(preImplosionOutPos + offset);
                    if (implosionPreOutPos.isInIndex()) {
                        CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                                implosionPreOutPos.getHolderPos(),
                                implosionPreOutPos.getCapacitorPos());
                        if (capacitorBean.isNormal()) {
                            reply(true);
                            Log.e(TAG, "正常回复");
                        } else {
                            Log.e(TAG, "内爆回复");
                            replyImplosion();
                            capacitorBean.setEmpty(true);
                            capacitorBeanBox.put(capacitorBean);
                            EventBus.getDefault().post(new ImplosionCountEvent());
                        }
                    } else {
                        reply(true);
                        Log.e(TAG, "正常回复 chainLength 异常");
                    }
                } else {
                    //内爆结果不进行分选，直接回复
                    reply(true);
                    Log.e(TAG, "正常回复 内爆不参与分选");
                }

                int curSerialNumber = calculate2Int(frameData[107], frameData[108]);
                Log.e(TAG, "curSerialNumber = " + curSerialNumber + " serialNumber = " + serialNumber);
                if (curSerialNumber != serialNumber) {
                    serialNumber = curSerialNumber;
                    OneStepInfo info = new OneStepInfo(
                            //如果有进料则进料二维码第一个字符为字母
                            isLetter(frameData[3]),
                            new String(frameData, 3, 16),
                            getResult(frameData[19], 1),
                            getResult(frameData[19], 2),
                            getResult(frameData[19], 3),
                            getResult(frameData[19], 4),
                            getResult(frameData[19], 5),
                            getByteResult(frameData[19], 7),
                            composeByteResult(getByteBit(frameData[19], 8),
                            getByteBit(frameData[20], 1)),
                            getByteResult(frameData[20], 3),
                            getResult(frameData[20], 4),
                            getResult(frameData[20], 5),
                            getByteResult(frameData[20], 7),
                            getResult(frameData[20], 8),
                            getResult(frameData[21], 1),
                            getLevel(frameData[21]),
                            getResult(frameData[21], 6),
                            getResult(frameData[21], 7),
                            calculate2Int(frameData[23], frameData[24]),
                            calculate2Int(frameData[25], frameData[26]),
                            calculate2Int(frameData[27], frameData[28]),
                            calculate2Int(frameData[29], frameData[30]),
                            new String(frameData, 31, 6),
                            new String(frameData, 37, 5),
                            new String(frameData, 43, 7),
                            new String(frameData, 52, 7),
                            new String(frameData, 59, 7),
                            new String(frameData, 67, 7),
                            new String(frameData, 76, 7),
                            new String(frameData, 83, 7),
                            new String(frameData, 91, 16),
                            getResult(frameData[21], 8),
                            false //TODO,暂时没有该字段
                    );

                    CountInfo countInfo = new CountInfo(frameData[116],frameData[115],frameData[118],frameData[117],
                            frameData[120],frameData[119],frameData[122],frameData[121],
                            frameData[124],frameData[123],frameData[126],frameData[125],
                            frameData[128],frameData[127]);
                    Log.e("xiaochunhui", countInfo.toStrings());
                    onChainMoveOneStep(info, curSerialNumber, countInfo);
//                    Log.e(TAG, "offset = " + offset);
                    offset = (offset + 1) % 21;
                    //保存当前的索引数据，以备下次重启使用
                    DataUtil.saveOffset(offset);
                    EventBus.getDefault().post(new ChainMoveOneStepEvent());
                } else {
                    handler.postDelayed(() -> {
                        reply(true);
                        Log.e(TAG, "与PLC通讯失败 增加回复");
                    }, 30);
                }
//                } else {
//                    Log.e(TAG, "校验失败");
//                    reply(false);
//                }
            }
            break;
            case 0x02: {
                //启动请求上报
            }
            break;
            case 0x03: {
                //电源电压，电流数据上报
                List<PowerSupplyBean> supplyBeanList = new ArrayList<>();
                for (int i = 0; i < 18; i++) {
                    int index = 3 + (i * 6);
                    supplyBeanList.add(createPowerSupplyBean(frameData[index], frameData[index + 1],
                            frameData[index + 2], frameData[index + 3],
                            frameData[index + 4], frameData[index + 5]));
                }
                EventBus.getDefault().post(new UpdatePowerSupplyEvent(supplyBeanList));

                EventBus.getDefault().post(new RealTimeVoltageEvent(
                        calculate2Int(frameData[111], frameData[112]),
                        calculate2Int(frameData[113], frameData[114]),
                        calculate2Int(frameData[115], frameData[116]),
                        calculate2Int(frameData[117], frameData[118]),
                        calculate2Int(frameData[119], frameData[120]),
                        calculate2Int(frameData[121], frameData[122]),
                        calculate2Int(frameData[123], frameData[124]),
                        calculate2Int(frameData[125], frameData[126]),
                        calculate2Int(frameData[127], frameData[128])));
            }
            break;
            case 0x04: {
                //异常状态上报
                final SparseIntArray intArray = new SparseIntArray();
                for (int i = 3; i < 29; i++) {
                    for (int j = 0, length = Constant.BitMask0.length; j < length; j++) {
                        if ((frameData[i] & Constant.BitMask0[j]) > 0) {
                            intArray.put(intArray.size(), ((i - 3) * 8) + (7 - j));
                        }
                    }
                }
                if (intArray.size() > 0) {
                    EventBus.getDefault().post(new AlarmEvent(intArray));
                } else {
                    EventBus.getDefault().post(new HideAlarmViewEvent());
                }
            }
            break;
            case 0x05: {
                //初始化动作完成上报
                EventBus.getDefault().post(new PlcReplyEvent(true));
            }
            break;
            case 0x06: {
                //烤箱内链条即将运动上报
                //发出事件，让红外模块暂停数据采集
                int curOvenMoveCount = calculate2Int(frameData[109], frameData[110]);
                Log.e("test", "curOvenMoveCount = " + curOvenMoveCount);
                if (ovenMoveCount != curOvenMoveCount) {
                    ovenMoveCount = curOvenMoveCount;
                    long curRunTime = System.currentTimeMillis();
                    long timeGap = curRunTime - lastRunTime;
                    if (timeGap > 10000L) {
                        lastRunTime = curRunTime;
                        EventBus.getDefault().post(new ChangeDetectStateEvent(false));
                        handler.postDelayed(ovenMoveOneStepEnd, 2500);
                    }
                    Log.e(TAG, "oven烤箱内链条即将运动");
                } else {
                    Logger.e("烤箱运动前帧数据重复发送");
                }
            }
            break;
            case 0x07: {
                //烤箱内链条运动之后上报
                Log.e(TAG, "烤箱内链条运动完成");
            }
            break;
            case 0x08: {
                //暂停(停止状态)状态上报
                Log.e(TAG, "暂停(停止状态)状态上报");
            }
            break;
            case 0x09: {
                //复位状态上报功能码
                //发出此事件，隐藏报警界面
                //实际PLC并没有发此功能码
                EventBus.getDefault().post(new HideAlarmViewEvent());
                Log.e(TAG, "复位状态上报功能码");
            }
            break;
            case 0xAA: {
                //应答成功
                handler.removeCallbacks(reSendDataRun);
                sendCount = 0;
                Log.e(TAG, "收到PLC成功应答");
                Log.e(TAG, "AA post plcReplayE");
                EventBus.getDefault().post(new PlcReplyEvent(false));
            }
            break;
            case 0xBB: {
                //应答失败
                handler.removeCallbacks(reSendDataRun);
                Log.e(TAG, "收到PLC失败应答");
                EventBus.getDefault().post(new CmdSendFailedEvent(2));
            }
            break;
            default:
                //逻辑上不可达
                Log.e(TAG, "analysisFrame 功能码解析错误");
                break;
        }
    }

    private PowerSupplyBean createPowerSupplyBean(int data1, int data2, int data3, int data4, int data5, int data6) {
        return new PowerSupplyBean(calculate2Int(data1, data2), calculate2Int(data3, data4),
                calculate2Int(data5, data6));
    }


    private boolean getResult(int b, int pos) {
        return (((1 << (pos - 1)) & 0xFF) & (byte) b) > 0;
    }

    private byte getLevel(int b) {
        return (byte) (((b << 3) & 0xFF) >> 4);
    }

    private byte getByteBit(int b, int pos) {
        return (byte) (getResult(b, pos) ? 1 : 0);
    }

    private byte composeByteResult(byte low, byte high) {
        return (byte) ((high << 1) + low);
    }

    private byte getByteResult(int b, int highPos) {
        return (byte) (((b << (8 - highPos)) & 0xFF) >> 6);
    }

    private int calculate2Int(int low, int high) {
        return low + (high << 8);
    }

    private static final byte[] replyTrue = {0x55, -0x56, 0x00, -0x01};
    private static final byte[] replyFalse = {0x55, -0x45, 0x00, -0x01};
    private static final byte[] implosionReply = {0x55, -0x55, 0x00, -0x01};

    private void reply(boolean proper) {
        try {
            mOutputStream.write(proper ? replyTrue : replyFalse);
            mOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "reply plc exception");
        }
    }

    private void replyImplosion() {
        try {
            mOutputStream.write(implosionReply);
            mOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "reply implosion exception");
        }
    }

    private byte[] lastBytes;
    private static int sendCount = 0;

    private Runnable reSendDataRun = new Runnable() {
        @Override
        public void run() {
            if (sendCount < 3) {
                sendBytes(lastBytes);
            } else {
                sendCount = 0;
                EventBus.getDefault().post(new CmdSendFailedEvent(1));
            }
        }
    };

    private void sendBytes(byte[] bytes) {
        try {
            if (lastBytes != bytes) {
                lastBytes = bytes;
            }
            mOutputStream.write(bytes);
            mOutputStream.flush();
            sendCount++;
            handler.postDelayed(reSendDataRun, 500);
//            MethodUtil.logHexBytes(TAG, bytes, 0, bytes.length, 10);
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "sendBytes exception");
        }
    }

    /**
     * 初始化
     */
    public static final byte INIT = 0x01;
    /**
     * 开始
     */
    public static final byte START = 0x02;
    /**
     * 暂停
     */
    public static final byte PAUSE = 0x03;
    /**
     * 重置
     */
    public static final byte RESET = 0x04;
    /**
     * 换料
     */
    public static final byte REPLACE = 0x05;

    /**
     * 继续运行
     */
    public static final byte GO_ON = 0x06;

    /**
     * 清除报警
     */
    public static final byte CLEAR_ALARM = 0x07;

    /**
     * 下发检测开关参数
     */
    public static final byte ENABLE_DETECT = 0x08;


    @IntDef({INIT, START, PAUSE, RESET, REPLACE, GO_ON, CLEAR_ALARM, ENABLE_DETECT})
    @Retention(RetentionPolicy.SOURCE)
    public @interface ControlCommand {
    }

    /**
     * 初始化命令为固定字节串
     */
    private static final byte[] initBytes = {0x55, 0x01, 0x00, -0x01};
    /**
     * 停止命令为固定字节串
     */
    private static final byte[] stopBytes = {0x55, 0x03, 0x00, -0x01};
    /**
     * 复位命令为固定字节串
     */
    private static final byte[] resetBytes = {0x55, 0x04, 0x00, -0x01};

    /**
     * 继续运行命令为固定字节串
     */
    private static final byte[] goOnBytes = {0x55, 0x06, 0x00, -0x01};

    /**
     * 继续运行命令为固定字节串
     */
    private static final byte[] clearAlarmBytes = {0x55, 0x07, 0x00, -0x01};

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onCmdEvent(CmdEvent event) {
        Log.e("sum = ", "e==" + event.getCmdType() + "");
        switch (event.getCmdType()) {
            case INIT: {
                sendBytes(initBytes);
                EventBus.getDefault().post(new OperationInfoEvent(operateString[1]));
            }
            break;
            case START: {
                sendBytes(combineParameterBytes(event.getParameter(), false));
                EventBus.getDefault().post(new OperationInfoEvent(operateString[2] + ",批号为:"
                        + event.getParameter().getBatchId()));
            }
            break;
            case PAUSE: {
                sendBytes(stopBytes);
                EventBus.getDefault().post(new OperationInfoEvent(operateString[3]));
            }
            break;
            case RESET: {
                sendBytes(resetBytes);
            }
            break;
            case REPLACE: {
                //组装数据
                sendBytes(combineParameterBytes(event.getParameter(), true));
                EventBus.getDefault().post(new OperationInfoEvent(operateString[5]
                        + ",批号为:" + event.getParameter().getBatchId()));
            }
            break;
            case GO_ON: {
                sendBytes(goOnBytes);
                EventBus.getDefault().post(new OperationInfoEvent(operateString[6]));
            }
            break;
            case CLEAR_ALARM: {
                sendBytes(clearAlarmBytes);
                EventBus.getDefault().post(new OperationInfoEvent(operateString[7]));
            }
            break;
            case ENABLE_DETECT: {
                byte[] bytes = new byte[273];
                bytes[0] = 0x55;
                bytes[1] = 0x08;
                DetectionFlagBean flagBean = event.getDetectionFlagBean();
                bytes[3] = flag2Byte(flagBean.isOpenCircuitEnable());
                bytes[4] = flag2Byte(flagBean.isShortCircuitEnable());
                bytes[5] = flag2Byte(flagBean.isUnAgeEnable());
                bytes[6] = flag2Byte(flagBean.isLeakCurrentEnable());
                bytes[7] = flag2Byte(flagBean.isCapacityEnable());
                bytes[8] = flag2Byte(flagBean.isLossAngleEnable());
                bytes[9] = flag2Byte(flagBean.isEsrEnable());
                bytes[10] = flag2Byte(flagBean.isSurgeEnable());
                bytes[11] = flag2Byte(flagBean.isImplosionEnable());
                bytes[12] = flag2Byte(flagBean.isPowerSupplyAlarmEnable());
                bytes[13] = flag2Byte(flagBean.isTemperatureAlarmEnable());
                bytes[14] = flag2Byte(flagBean.isCamera1Enable());
                bytes[15] = flag2Byte(flagBean.isCamera2Enable());
                bytes[16] = flag2Byte(flagBean.isCamera3Enable());
                bytes[17] = flag2Byte(flagBean.isSprayCodeEnable());
                bytes[18] = flag2Byte(flagBean.isAutoModeEnable());
                bytes[272] = (byte) 0xFF;
                sendBytes(bytes);
                EventBus.getDefault().post(new OperationInfoEvent(operateString[8]));
            }
            default:
                break;
        }
    }

    private byte flag2Byte(boolean flag) {
        return flag ? (byte) 1 : (byte) 0;
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onIndexInit(IndexInitEvent event) {
        offset = 0;
        Log.e(TAG, "offset init");
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onReplyPlc(ReplyPlcEvent event) {
        reply(event.isProper());
        Log.e(TAG, "回复PLC = " + (event.isProper() ? "0xAA" : "0xBB"));
    }

    private byte[] combineParameterBytes(ProcessParameter parameter, boolean isReplace) {
        byte[] bytes = new byte[273];
        bytes[0] = 0x55;
        bytes[1] = (byte) (isReplace ? 0x05 : 0x02);
        bytes[2] = 0x00;
        set2Byte(parameter.getPowerV1(), bytes, 3);
        set2Byte(parameter.getPowerI1(), bytes, 5);
        set2Byte(parameter.getPowerV2(), bytes, 7);
        set2Byte(parameter.getPowerI2(), bytes, 9);
        set2Byte(parameter.getPowerV3(), bytes, 11);
        set2Byte(parameter.getPowerI3(), bytes, 13);
        set2Byte(parameter.getPowerV4(), bytes, 15);
        set2Byte(parameter.getPowerI4(), bytes, 17);
        set2Byte(parameter.getPowerV5(), bytes, 19);
        set2Byte(parameter.getPowerI5(), bytes, 21);
        set2Byte(parameter.getPowerV6(), bytes, 23);
        set2Byte(parameter.getPowerI6(), bytes, 25);
        set2Byte(parameter.getPowerV7(), bytes, 27);
        set2Byte(parameter.getPowerI7(), bytes, 29);
        set2Byte(parameter.getPowerV8(), bytes, 31);
        set2Byte(parameter.getPowerI8(), bytes, 33);
        set2Byte(parameter.getPowerV9(), bytes, 35);
        set2Byte(parameter.getPowerI9(), bytes, 37);
        set2Byte(parameter.getPowerV10(), bytes, 39);
        set2Byte(parameter.getPowerI10(), bytes, 41);
        set2Byte(parameter.getPowerV11(), bytes, 43);
        set2Byte(parameter.getPowerI11(), bytes, 45);
        set2Byte(parameter.getPowerV12(), bytes, 47);
        set2Byte(parameter.getPowerI12(), bytes, 49);
        set2Byte(parameter.getPowerV13(), bytes, 51);
        set2Byte(parameter.getPowerI13(), bytes, 53);
        set2Byte(parameter.getPowerV14(), bytes, 55);
        set2Byte(parameter.getPowerI14(), bytes, 57);
        set2Byte(parameter.getPowerV15(), bytes, 59);
        set2Byte(parameter.getPowerI15(), bytes, 61);
        set2Byte(parameter.getPowerV16(), bytes, 63);
        set2Byte(parameter.getPowerI16(), bytes, 65);
        set2Byte(parameter.getPowerV17(), bytes, 67);
        set2Byte(parameter.getPowerI17(), bytes, 69);
        set2Byte(parameter.getPowerV18(), bytes, 71);
        set2Byte(parameter.getPowerI18(), bytes, 73);
        set2Byte(parameter.getChargeV(), bytes, 75);
        set2Byte(parameter.getSurgeV(), bytes, 77);
        set2Byte(parameter.getTestV(), bytes, 79);
        set2Byte(parameter.getOvenTemperature(), bytes, 81);
        set2Byte(parameter.getShortCircuitV(), bytes, 83);
        set2Byte(parameter.getOpenCircuitV(), bytes, 85);
        setLimitBytes(parameter.getLeakageUpperLimit() / 10f, bytes, 87, "1HI:".getBytes(), UA.getBytes());
        setLimitBytes(parameter.getLeakageMiddleLimit() / 10f, bytes, 99, "1MD:".getBytes(), UA.getBytes());
        setLimitBytes(parameter.getLeakageLowerLimit() / 10f, bytes, 111, "1LO:".getBytes(), UA.getBytes());
        setLimitBytes(parameter.getCapacitorNominal(), bytes, 123, "STD:".getBytes(), UF.getBytes());
        setLimitBytes(parameter.getPremiumLimit(), bytes, 135, "P1H:".getBytes(), UF.getBytes());
        setLimitBytes(parameter.getSuperiorLowerLimit(), bytes, 147, "P1L:".getBytes(), UF.getBytes());
        setLimitBytes(parameter.getGoodProductUpperLimit(), bytes, 159, "P2H:".getBytes(), UF.getBytes());
        setLimitBytes(parameter.getGoodProductLowerLimit(), bytes, 171, "P2L:".getBytes(), UF.getBytes());
        setLimitBytes(parameter.getGoodProduct2UpperLimit(), bytes, 183, "P3H:".getBytes(), UF.getBytes());
        setLimitBytes(parameter.getGoodProduct2LowerLimit(), bytes, 195, "P3L:".getBytes(), UF.getBytes());
        setLimitBytes(parameter.getLossAngelUpperLimit() / 1000f, bytes, 207, "DHI:".getBytes(), OO.getBytes());
        setLimitBytes(parameter.getUpperImpedanceLimit(), bytes, 219, "R2H:".getBytes(), OO.getBytes());

        set2Byte(parameter.getUnAgedVoltage(), bytes, 231);
        set2Byte(parameter.getUpperTemperatureLimit(), bytes, 233);
        set2Byte(parameter.getAgingTime(), bytes, 235);
        set2Byte(parameter.getInstrumentFrequency(), bytes, 237);

        bytes[239] = (byte) parameter.getCodingMark().charAt(0);
        bytes[240] = (byte) parameter.getCodingMark().charAt(1);
        bytes[241] = (byte) parameter.getCodingMark().charAt(2);
        bytes[242] = (byte) parameter.getCodingMark().charAt(3);
        bytes[243] = (byte) parameter.getCodingMark().charAt(4);
        bytes[244] = (byte) parameter.getCodingMark().charAt(5);
        bytes[245] = (byte) parameter.getCodingMark().charAt(6);
        bytes[246] = (byte) parameter.getCodingMark().charAt(7);

        bytes[247] = (byte) parameter.getCodingStartNumber().charAt(0);
        bytes[248] = (byte) parameter.getCodingStartNumber().charAt(1);
        bytes[249] = (byte) parameter.getCodingStartNumber().charAt(2);
        bytes[250] = (byte) parameter.getCodingStartNumber().charAt(3);
        bytes[251] = (byte) parameter.getCodingStartNumber().charAt(4);
        bytes[252] = (byte) parameter.getCodingStartNumber().charAt(5);
        bytes[253] = (byte) parameter.getCodingStartNumber().charAt(6);
        bytes[254] = (byte) parameter.getCodingStartNumber().charAt(7);
        set2Byte(parameter.getFeedInTableHeight(), bytes, 255);
        set2Byte(parameter.getFeedInAngle(), bytes, 257);
        set2Byte(parameter.getDischargeAngle(), bytes, 259);
        set2Byte(parameter.getDischargeTableHeight(), bytes, 261);
        set2Byte(parameter.getChargeI(), bytes, 263);
        set2Byte(parameter.getSurgeI(), bytes, 265);
        set2Byte(parameter.getTestI(), bytes, 267);
        //剩下两个byte(269,270)备用
        int sum = 0;
        for (int i = 3; i <= 270; i++) {
            if (i % 2 == 1) {
                sum = sum + (bytes[i] & 0xFF) + (bytes[i + 1] << 8);
            }
        }
        bytes[271] = (byte) (sum % 256);
        bytes[272] = (byte) 0xFF;
//        Log.e(TAG, "sum = " + (bytes[271] & 0xFF));
//        logDatas(bytes, bytes.length - 1);
        return bytes;
    }

    private void set2Byte(int value, byte[] bytes, int startPos) {
        bytes[startPos] = (byte) (value & 0xff);
        bytes[startPos + 1] = (byte) (value >> 8);
    }

    /**
     * 1.漏电流上限：1HI:123456uA  共占12字节
     * 2.漏电流中限：1MD:123456uA
     * 3.漏电流下限：1LO:123456uA
     * 4.电容标称：  STD:123456uF
     * 5.优品上限：  P1H:123456uF
     * 6.优品下限：  P1L:123456uF
     * 7.良品上限：  P2H:123456uF
     * 8.良品下限：  P2L:123456uF
     * 9.良品2上限： P3H:123456uF
     * 10.良品2下限：P3L:123456uF
     * 11.损失上限： DHI:12345600
     * 12.阻抗上限： R2H:12345600
     *
     * @param value 设置给仪表的参数值
     */
    private void setLimitBytes(int value, byte[] bytes, int startPos, byte[] startChars, byte[] endChars) {
        for (int i = 0; i < startChars.length; i++) {
            bytes[startPos + i] = startChars[i];
        }
        char[] valueChars = String.valueOf(value).toCharArray();
        int zeroCount = 6 - valueChars.length;
        int zeroStartPos = startPos + startChars.length;
        for (int i = 0; i < zeroCount; i++) {
            bytes[zeroStartPos + i] = (byte) '0';
        }
        int valueStartPos = startPos + startChars.length + zeroCount;
        for (int i = 0; i < valueChars.length; i++) {
            bytes[valueStartPos + i] = (byte) valueChars[i];
        }
        int endCharPos = startPos + startChars.length + zeroCount + valueChars.length;
        for (int i = 0; i < endChars.length; i++) {
            bytes[endCharPos + i] = endChars[i];
        }
    }

    private void setLimitBytes(float value, byte[] bytes, int startPos, byte[] startChars, byte[] endChars) {
        for (int i = 0; i < startChars.length; i++) {
            bytes[startPos + i] = startChars[i];
        }
        char[] valueChars = String.valueOf(value).toCharArray();
        int zeroCount = 6 - valueChars.length;
        int zeroStartPos = startPos + startChars.length;
        for (int i = 0; i < zeroCount; i++) {
            bytes[zeroStartPos + i] = (byte) '0';
        }
        int valueStartPos = startPos + startChars.length + zeroCount;
        for (int i = 0; i < valueChars.length; i++) {
            bytes[valueStartPos + i] = (byte) valueChars[i];
        }
        int endCharPos = startPos + startChars.length + zeroCount + valueChars.length;
        for (int i = 0; i < endChars.length; i++) {
            bytes[endCharPos + i] = endChars[i];
        }
    }

    private static final String TypeLeakCurrent1 = "leakCurrent1";
    private static final String TypeLeakCurrent2 = "leakCurrent2";
    private static final String TypeCapacity1 = "capacitor1";
    private static final String TypeCapacity2 = "capacitor2";

    //短路测试工位在链条上的原始工位位置
    private static final int shortCircuitPos = 17;
    //开路测试工位在链条上的原始工位位置
    private static final int openCircuitPos = 25;
    //进料工位在链条上的原始工位位置
    private static final int capacitorInPos = 33;
    //出料被夹取的工位在链条上的初始位置
    private static final int outPos = 71;
    //容量1阻抗1损失角1工位在链条上的原始工位位置
    private static final int capacity1Pos = 72;
    //漏电流2测试工位在链条上的原始工位位置
    private static final int leakCurrent2Pos = 80;
    //漏电流1测试工位在链条上的原始工位位置
    private static final int leakCurrent1Pos = 82;
    //红外测温工位在链条上的原始工位位置
    private static final int tempPos = 110;
    //浪涌1检测工位
    private static final int surge1Pos = 116;
    //浪涌1工位的前一个工位
    private static final int preSurge1Pos = 117;
    //浪涌2检测工位
    private static final int surge2Pos = 111;
    //浪涌2
    private static final int preSurge2Pos = 112;
    //内爆推料的前一个位置
    private static final int preImplosionOutPos = 118;
    //凸顶和未老化测试工位在链条上的原始工位位置
    private static final int convexAndUnAgePos = 122;

    private int offset = DataUtil.offsetBean.getOffset();
    private int serialNumber = 0;

    private CapacitorBean outCapacitorBean = null;

    private int last_holderPos = -1;

    private void onChainMoveOneStep(OneStepInfo event, int serialNumber, CountInfo countInfo) {

        final int time = (int) (System.currentTimeMillis() / 1000L);

        //上传短路检测数据
        final int curShortCircuitPos = shortCircuitPos + offset;
        final PosBean shortCircuitPosBen = DataUtil.getChainPosBean(curShortCircuitPos);
        if (shortCircuitPosBen.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                    shortCircuitPosBen.getHolderPos(), shortCircuitPosBen.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                final CircuitData circuitData = new CircuitData(capacitorBean.getUid(), event.getShortCircuit(),
                        bool2Int(event.isShortCircuitResult()));
                final ShortCircuitJsonObj shortCircuitJsonObj = new ShortCircuitJsonObj(null, time, circuitData);
                EventBus.getDefault().post(new SendJsonObjEvent(shortCircuitJsonObj));
                //电容短路则将此位置上的电容信息删除
                deleteChainCapacitor(event.isShortCircuitResult(), capacitorBean, shortCircuitPosBen);
            }
        }

        //上传开路检测数据
        final int curOpenCircuitPos = openCircuitPos + offset;
        final PosBean openCircuitPosBean = DataUtil.getChainPosBean(curOpenCircuitPos);
        if (openCircuitPosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                    openCircuitPosBean.getHolderPos(), openCircuitPosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                final CircuitData circuitData =
                        new CircuitData(capacitorBean.getUid(), event.getOpenCircuit(),
                                bool2Int(event.isOpenCircuitResult()));
                final OpenCircuitJsonObj openCircuitJsonObj =
                        new OpenCircuitJsonObj(null, time, circuitData);
                EventBus.getDefault().post(new SendJsonObjEvent(openCircuitJsonObj));
                //电容开路或对射光纤检测到该工位无电容，则将此位置上的电容信息删除
                deleteChainCapacitor(event.isOpenCircuitResult() || event.isCheckEmpty(),
                        capacitorBean, openCircuitPosBean);
            }
        }

        final int inPos = capacitorInPos + offset;
        final PosBean inPosBean = DataUtil.getChainPosBean(inPos);
        if (inPosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(inPosBean.getHolderPos(),
                    inPosBean.getCapacitorPos());
            //有进料，上传电容ID到服务器
            if (event.isFeedIn()) {
                final String curUid = event.getFeedCapacitorId() + "_" + serialNumber;
                final CapacitorIdData idData = new CapacitorIdData(curUid,
                        event.getFeedCapacitorId(), DataUtil.producingParameter.getBatchId());
                final CapacitorIdJsonObj idJsonObj = new CapacitorIdJsonObj("uid", time, idData);
                EventBus.getDefault().post(new SendJsonObjEvent(idJsonObj));
                capacitorBean.setUid(curUid);
                capacitorBean.setEmpty(false);
                EventBus.getDefault().post(new ChainCapacitorUpdateEvent(capacitorBean.getUid(),
                        false, inPosBean.getHolderPos(), inPosBean.getCapacitorPos()));
                if(last_holderPos == inPosBean.getHolderPos()){
                    DataUtil.ovenLastCapacitorUid = capacitorBean.getUid();
                }
            } else {
                capacitorBean.setUid("");
                capacitorBean.setEmpty(true);
                EventBus.getDefault().post(new ChainCapacitorUpdateEvent("",
                        true, inPosBean.getHolderPos(), inPosBean.getCapacitorPos()));
            }
            last_holderPos = inPosBean.getHolderPos();
            capacitorBeanBox.put(capacitorBean);
        }

        if (!outCapacitorBean.isEmpty()) {
            //上传容量2、阻抗2、损失角2 检测数据和结果
            CapacityData capacitorData = new CapacityData(outCapacitorBean.getUid(),
                    getCapacity(event.getCapacity2()),
                    event.getCapacityResult2(),
                    getLossAngle(event.getLossAngle2()),
                    bool2Int(event.isLossAngleResult2()),
                    getImpedance(event.getImpedance2()),
                    bool2Int(event.isImpedanceResult2()));
            if(!outCapacitorBean.getUid().isEmpty() && !DataUtil.lastCapacitorUidQueue.isEmpty()
                    && DataUtil.lastCapacitorUidQueue.contains(outCapacitorBean.getUid())){//出料最后为批次最后一个电容，切换单号为下一批次
                DataUtil.lastCapacitorUidQueue.remove(outCapacitorBean.getUid());
                DataUtil.FlowCardBatchIdProducing = DataUtil.FlowCardBatchId;
            }
            CapacityJsonObj capacitorJsonObj = new CapacityJsonObj(TypeCapacity2, time, capacitorData);
            EventBus.getDefault().post(new SendJsonObjEvent(capacitorJsonObj));
            Log.e(TAG, "上传容量2、阻抗2、损失角2 检测数据和结果");
            //上传电容等级信息
            CapacitorLevelData levelData = new CapacitorLevelData(outCapacitorBean.getUid(),
                    event.getCapacitorGrade());
            CapacitorLevelJsonObj levelJsonObj = new CapacitorLevelJsonObj(null, time, levelData);
            EventBus.getDefault().post(new SendJsonObjEvent(levelJsonObj));
        }

        final int curOutPos = outPos + offset;
        final PosBean outPosBean = DataUtil.getChainPosBean(curOutPos);
        if (outPosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                    outPosBean.getHolderPos(), outPosBean.getCapacitorPos());
            //下一次它被移至出料中转台,提前记录
            outCapacitorBean.setEmpty(capacitorBean.isEmpty());
            outCapacitorBean.setUid(capacitorBean.getUid());
            //此位置上的电容将被抓取到出料中转台，所以所有参数复位。
            capacitorBean.setVoltage(0);
            capacitorBean.setCurrent(0);
            capacitorBean.setNormal(true);
            capacitorBean.setUid("");
            capacitorBean.setEmpty(true);
            capacitorBeanBox.put(capacitorBean);
            EventBus.getDefault().post(new ChainCapacitorUpdateEvent("", true,
                    outPosBean.getHolderPos(), outPosBean.getCapacitorPos()));
        }

        //上传容量1、阻抗1、损失角1 检测数据和结果
        final int curCapacity1Pos = capacity1Pos + offset;
        final PosBean capacity1PosBean = DataUtil.getChainPosBean(curCapacity1Pos);
        if (capacity1PosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                    capacity1PosBean.getHolderPos(), capacity1PosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                CapacityData capacitorData = new CapacityData(capacitorBean.getUid(),
                        getCapacity(event.getCapacity1()),
                        event.getCapacityResult1(),
                        getLossAngle(event.getLossAngle1()),
                        bool2Int(event.isLossAngleResult1()),
                        getImpedance(event.getImpedance1()),
                        bool2Int(event.isImpedanceResult1()));
                CapacityJsonObj capacitorJsonObj = new CapacityJsonObj(TypeCapacity1, time, capacitorData);
                EventBus.getDefault().post(new SendJsonObjEvent(capacitorJsonObj));
            }
        }

        //上传漏电流2检测数据与结果
        final int curLeakCurrent2Pos = leakCurrent2Pos + offset;
        final PosBean leakCurrent2PosBean = DataUtil.getChainPosBean(curLeakCurrent2Pos);
        if (leakCurrent2PosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                    leakCurrent2PosBean.getHolderPos(), leakCurrent2PosBean.getCapacitorPos()
            );
            if (!capacitorBean.isEmpty()) {
                Log.e(TAG, "上传漏电流2检测数据与结果");
                LeakCurrentData leakCurrentData = new LeakCurrentData(capacitorBean.getUid(),
                        getCurrent(event.getLeakCurrent2()), event.getLeakCurrentResult2());
                LeakCurrentJsonObj leakCurrentJsonObj = new LeakCurrentJsonObj(TypeLeakCurrent2, time, leakCurrentData);
                EventBus.getDefault().post(new SendJsonObjEvent(leakCurrentJsonObj));
            }
        }

        //上传漏电流1检测数据与结果
        final int curLeakCurrent1Pos = leakCurrent1Pos + offset;
        final PosBean leakCurrent1PosBean = DataUtil.getChainPosBean(curLeakCurrent1Pos);
        if (leakCurrent1PosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                    leakCurrent1PosBean.getHolderPos(), leakCurrent1PosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                Log.e(TAG, "上传漏电流1检测数据与结果");
                LeakCurrentData leakCurrentData = new LeakCurrentData(capacitorBean.getUid(),
                        getCurrent(event.getLeakCurrent1()), event.getLeakCurrentResult1());
                LeakCurrentJsonObj leakCurrentJsonObj = new LeakCurrentJsonObj(TypeLeakCurrent1, time, leakCurrentData);
                EventBus.getDefault().post(new SendJsonObjEvent(leakCurrentJsonObj));
            }
        }

        //上传红外测温数据与结果
        final int curTempPos = tempPos + offset;
        final PosBean tempPosBean = DataUtil.getChainPosBean(curTempPos);
        if (tempPosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(
                    tempPosBean.getHolderPos(), tempPosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                TemperatureData temperatureData = new TemperatureData(capacitorBean.getUid(),
                        event.getTemperature(), bool2Int(event.isTemperateResult()));
                TemperatureJsonObj temperatureJsonObj =
                        new TemperatureJsonObj(null, time, temperatureData);
                EventBus.getDefault().post(new SendJsonObjEvent(temperatureJsonObj));
                Log.e(TAG, "上传红外测温数据与结果");
                deleteChainCapacitor(event.isTemperateResult(), capacitorBean, tempPosBean);
            }
        }

        //上传浪涌2检测结果
        final int curSurge2Pos = surge2Pos + offset;
        final PosBean surge2PosBean = DataUtil.getChainPosBean(curSurge2Pos);
        if (surge2PosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(surge2PosBean.getHolderPos(),
                    surge2PosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                ResultData resultData = new ResultData(capacitorBean.getUid(), bool2Int(event.isSurge2()));
                DetectionResult detectionResult = new DetectionResult(DetectionResult.SURGE2, time, resultData);
                EventBus.getDefault().post(new SendJsonObjEvent(detectionResult));
                Log.e(TAG, "上传浪涌2检测结果");
                deleteChainCapacitor(event.isSurge2(), capacitorBean, surge2PosBean);
            }
        }

        //上传浪涌1检测结果
        final int curSurge1Pos = surge1Pos + offset;
        final PosBean surge1PosBean = DataUtil.getChainPosBean(curSurge1Pos);
        if (surge1PosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(surge1PosBean.getHolderPos(),
                    surge1PosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                ResultData resultData = new ResultData(capacitorBean.getUid(), bool2Int(event.isSurge1()));
                DetectionResult detectionResult = new DetectionResult(DetectionResult.SURGE1, time, resultData);
                EventBus.getDefault().post(new SendJsonObjEvent(detectionResult));
                Log.e(TAG, "上传浪涌1检测结果");
                deleteChainCapacitor(event.isSurge1(), capacitorBean, surge1PosBean);
            }
        }

        //上传未老化检测结果和凸顶检测结果
        final int unAgeCapacitorPos = convexAndUnAgePos + offset;
        final PosBean unAgePosBean = DataUtil.getChainPosBean(unAgeCapacitorPos);
        if (unAgePosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(unAgePosBean.getHolderPos(),
                    unAgePosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                final UnAgeData unAgeData = new UnAgeData(capacitorBean.getUid(), event.getUnAge(),
                        bool2Int(event.isUnAgeResult()));
                final UnAgeJsonObj unAgeJsonObj = new UnAgeJsonObj(null, time, unAgeData);
                EventBus.getDefault().post(new SendJsonObjEvent(unAgeJsonObj));
                Log.e(TAG, "上传未老化检测结果和凸顶检测结果");
                ResultData resultData = new ResultData(capacitorBean.getUid(), bool2Int(event.isConvexResult()));
                DetectionResult detectionResult = new DetectionResult(DetectionResult.CONVEX, time, resultData);
                EventBus.getDefault().post(new SendJsonObjEvent(detectionResult));
                deleteChainCapacitor(event.isUnAgeResult() || event.isConvexResult(),
                        capacitorBean, unAgePosBean);
            }
        }

        /**由于浪涌模块不知道该位置上的电容的uid，所以在浪涌检测之前，将该位置上的UID发出，以队列的形式保存，
         * 当检测浪涌时，将此uid数据从队列头部获取，就是该浪涌数据对应的uid*/
        final int curPreSurge1Pos = preSurge1Pos + offset;
        final PosBean preSurge1PosBean = DataUtil.getChainPosBean(curPreSurge1Pos);
        if (preSurge1PosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(preSurge1PosBean.getHolderPos(),
                    preSurge1PosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                EventBus.getDefault().post(new SurgeUidEvent(1, capacitorBean.getUid()));
            }
        }

        /**由于浪涌模块不知道该位置上的电容的uid，所以在浪涌检测之前，将该位置上的UID发出，以队列的形式保存，
         * 当检测浪涌时，将此uid数据从队列头部获取，就是该浪涌数据对应的uid*/
        final int curPreSurge2Pos = preSurge2Pos + offset;
        final PosBean preSurge2PosBean = DataUtil.getChainPosBean(curPreSurge2Pos);
        if (preSurge2PosBean.isInIndex()) {
            CapacitorBean capacitorBean = DataUtil.getChainCapacitorBean(preSurge2PosBean.getHolderPos(),
                    preSurge2PosBean.getCapacitorPos());
            if (!capacitorBean.isEmpty()) {
                EventBus.getDefault().post(new SurgeUidEvent(2, capacitorBean.getUid()));
            }
        }

        if (offset == 20) {
            if (DataUtil.flagBean.isAutoModeEnable()) {//自动运行模式
                DataUtil.holderMoveIntoOven();
                EventBus.getDefault().post(new ChainHolderIntoOvenEvent());
            } else {
                DataUtil.chainHolderCircleMove();
            }
        }

        String dischargeCapacitorId = event.getDischargeCapacitorId();

        //发送实时统计数据
        boolean qrCodeError = isQrCodeError(event.getDischargeCapacitorId());
        boolean isProduce = !outCapacitorBean.isEmpty()//不是空位
                && (!outCapacitorBean.getUid().isEmpty())//有id
                && "-1".equals(outCapacitorBean.getUid());//不是默认值
        final CountUpdateEvent countUpdateEvent = new CountUpdateEvent(
                qrCodeError, event.isShortCircuitResult(),
                event.isOpenCircuitResult(), event.isConvexResult(), event.isUnAgeResult(),
                event.isTemperateResult(), event.isSurge1(), event.isSurge2(), event.isFeedIn(),
                //isLetter(dischargeCapacitorId.charAt(0)),
                isProduce,
                event.getCapacitorGrade(),
                event.getTemperature(), event.getLeakCurrent1(), event.getCapacity1(),
                event.getLossAngle1(), event.getImpedance1(), event.getLeakCurrent2(),
                event.getCapacity2(), event.getLossAngle2(), event.getImpedance2(), event.isAcuteMaladyCount(),countInfo);
        EventBus.getDefault().post(countUpdateEvent);
    }

    private void deleteChainCapacitor(boolean result, CapacitorBean bean, PosBean posBean) {
        if (result) {
            bean.setEmpty(true);
            bean.setUid("");
            bean.setNormal(true);
            bean.setCurrent(0);
            bean.setVoltage(0);
            capacitorBeanBox.put(bean);
            EventBus.getDefault().post(new ChainCapacitorUpdateEvent("", true,
                    posBean.getHolderPos(), posBean.getCapacitorPos()));
        }
    }

    private int getImpedance(String impedance) {
        String valueStr = impedance.trim();
        try {
            if (valueStr.length() > 0) {
                return (int) (Float.valueOf(impedance.trim()) * 100);
            }
        } catch (NumberFormatException e) {
            String msg = e.getMessage();
            if (msg != null) {
                Log.e(TAG, msg);
            }
            return 0;
        }
        return 0;
    }

    private int getCurrent(String str) {
        String valueStr = str.trim();
        try {
            if (valueStr.length() > 0) {
                return (int) (Float.valueOf(str.trim()) * 10);
            }
        } catch (NumberFormatException e) {
            return 0;
        }
        return 0;
    }

    private int getCapacity(String capacity) {
        String valueStr = capacity.trim();
        try {
            if (valueStr.length() > 0) {
                return (int) (Float.valueOf(valueStr) * 100);
            }
        } catch (NumberFormatException e) {
            return 0;
        }
        return 0;
    }

    private int getLossAngle(String loss) {
        String valueStr = loss.trim();
        try {
            if (valueStr.length() > 0) {
                return (int) (Double.valueOf(valueStr) * 100000);
            }
        } catch (NumberFormatException e) {
            return 0;
        }
        return 0;
    }

    private int bool2Int(boolean bool) {
        return bool ? 1 : 0;
    }

    private Runnable ovenMoveOneStepEnd = () -> {
        DataUtil.holderMoveIntoChain();
        final HolderBean holderBean = DataUtil.chainHolderList.peekLast();
        if (holderBean != null) {
            final List<String> uidList = new ArrayList<>();
            for (int i = 1, size = holderBean.capacitorList.size(); i < size; i++) {
                final CapacitorBean capacitorBean = holderBean.capacitorList.get(i);
                if (!capacitorBean.isEmpty()) {
                    uidList.add(capacitorBean.getUid());
                }
            }
            if (uidList.size() > 0) {
                //上传出烤箱的那条夹具的电容uid
                CompleteUidJsonObj jsonObj = new CompleteUidJsonObj("", System.currentTimeMillis(), uidList);
                EventBus.getDefault().post(new SendJsonObjEvent(jsonObj));
            }
        }
        EventBus.getDefault().post(new ChangeDetectStateEvent(true));
    };

    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(this);
        if (mSerialPort != null) {
            mSerialPort.close();
            mSerialPort = null;
        }
        canRun = false;
        runThread.interrupt();
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    private boolean isLetter(int a) {
        return (a >= 65 && a <= 90) || (a >= 97 && a <= 122);
    }

    private boolean isNumber(int n) {
        return n >= 48 && n <= 57;
    }

    private boolean isQrCodeError(String qrStr) {
        if(qrStr.length() > 2){//首2个字符不是字母则为false
            int code1 = qrStr.codePointAt(0);
            int code2 = qrStr.codePointAt(1);
            if(!(isLetter(code1) && isLetter(code2))){
                return false;
            }
        } else {
            return false;
        }
        for (int i = 2, length = qrStr.length(); i < length; i++) {// i = 0, i = 1做了检测
            int code = qrStr.codePointAt(i);
//            Log.e(TAG, "isQrCodeError: code = " + code);
            if (!(isNumber(code) || isLetter(code))) {
                return true;
            }
        }
        return false;
    }

    private boolean conversion(int a, int b){
        int i = a&b;
        return i > 0;
    }
}
